﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AlgoritimoGenetico.dados;
using System.IO;
using AlgoritimoGenetico.Properties;
using System.Security.Cryptography;

namespace AlgoritimoGenetico.utils
{
    public class GenericPair<TFirst,TSecond>
    {
        public GenericPair(TFirst first, TSecond second)
        {
            this.First = first;
            this.Second = second;
        }
        public TFirst First {get; set;}
        public TSecond Second {get; set;}
    }
    public class Utils
    {
        private static Random _Rand = new Random(13);
        public static int NumeroCidades = -1;
        public static Random Rand 
        { 
            get
            {
                return Utils._Rand;
            } 
        }
        public static List<GenericPair<string, int>> GetIndicesCidades()
        {
            List<GenericPair<string, int>> indicesCidades = new List<GenericPair<string, int>>();

            string[] cidadesTxt = Resources.Janeiro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0, j = 0; i < (cidadesTxt.Length - 1); i = i + 2, j++)
            {
                string nomeCidade = cidadesTxt[i].Trim(new char[] { '\r' });
                int indice = j;

                GenericPair<string, int> pair = new GenericPair<string, int>(nomeCidade, indice);

                indicesCidades.Add(pair);
            }
            return indicesCidades;
        }
        public static List<Cidade> LerCidades(DateTime mesReferencia)
        {
            List<Cidade> cidades = new List<Cidade>();
            string[] cidadesTxt = null;
            switch (mesReferencia.Month)
            {
                case 1 :
                    cidadesTxt = Resources.Janeiro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 2 :
                    cidadesTxt = Resources.Fevereiro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 3:
                    cidadesTxt = Resources.Marco.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 4:
                    cidadesTxt = Resources.Abril.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 5:
                    cidadesTxt = Resources.Maio.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 6:
                    //cidadesTxt = Resources.Cidades_PERNAMBUCO.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    cidadesTxt = Resources.Junho.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 7:
                    cidadesTxt = Resources.Julho.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 8:
                    cidadesTxt = Resources.Agosto.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 9:
                    cidadesTxt = Resources.Setembro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 10:
                    cidadesTxt = Resources.Outubro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 11:
                    cidadesTxt = Resources.Novembro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                case 12:
                    cidadesTxt = Resources.Dezembro.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    break;
                default:
                    throw new Exception("O mes de referencia não existe");
            }

            for (int i = 0; i < (cidadesTxt.Length - 1); i = i+2)
            {
                Cidade cidade = new Cidade
                    (
                        cidadesTxt[i].Trim(new char[]{'\r'}),
                        _ConverteStringEmCaracteristicas(cidadesTxt[i + 1].Trim(new char[]{'\r'}))
                    );
                if(cidadesTxt[i].Contains('#')) break;
                cidades.Add(cidade);
            }
            NumeroCidades = cidades.Count;
            return cidades;
        }

        public static float[,] LerDistanciaCidades()
        {
            float[,] distancia = new float[NumeroCidades, NumeroCidades];

            string[] distLinha = Resources.Distancias.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < (distLinha.Length); i++)
            {
                string[] cid = distLinha[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                for (int j = 0; j < cid.Length; j++)
                {
                    distancia[i, j] = float.Parse(cid[j].Trim('\r'));
                }
            }
            return distancia;
            
        }
        private static List<float> _ConverteStringEmCaracteristicas(string caracteristicas)
        {
            List<float> caracs = new List<float>();
   
            char[] charCaracs = caracteristicas.ToCharArray();

            foreach (char caracteristica in charCaracs)
            {
                try
                {
                    float carac = float.Parse(caracteristica.ToString());
                    caracs.Add(carac);
                }
                catch
                {
                }
            }
            return caracs;
        }

        public static void Shuffle<T>(IList<T> list)
        {
            RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
            int n = list.Count;
            while (n > 1)
            {
                byte[] box = new byte[1];
                do
                    provider.GetBytes(box);
                while (!(box[0] < n * (Byte.MaxValue / n)));

                int k = (box[0] % n);
                n--;
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }
        public static List<Cromossomo> Clone(List<Cromossomo> cromossomos)
        {
            List<Cromossomo> clones = new List<Cromossomo>(cromossomos.Count);

            foreach (Cromossomo cromossomo in cromossomos)
                clones.Add(cromossomo.Clone());

            return clones;
        }
        public static void AgruparCidadesCromossomo(Cromossomo cromossomo)
        {
            cromossomo.Genes.Sort(delegate(Gene g1, Gene g2) { return g2.Nome.CompareTo(g1.Nome); });
        }
    }
}
